# coding = gbk

import bpy
import bmesh
import struct
import mathutils
import math
import ctypes

from bpy_extras.io_utils import (ImportHelper,
							ExportHelper,
							path_reference_mode,
							axis_conversion,
							)

from bpy.props import BoolProperty
from bpy.props import EnumProperty
from bpy.props import StringProperty


#import os,sys
#sys.path.append("D:/U/Project/图像引擎/插件")

#import SceneObj



E_网格模型     = 1
E_网格地形     = 5
E_导航        = 10
E_关键帧      = 11
E_关键帧片段   = 12

E_关键帧_location      = 20
E_关键帧_roation       = 21
E_关键帧_scale         = 22


OT_FLUID = 30

EXPORT_APPLY_MODIFIERS_RENDER=False



#保存对象名称
def SaveObjName(file, name):
	#保存文本数量
	strName = bytes(name, encoding = 'gbk')
	file.write( struct.pack('<I', len(strName)) )
	for i in range(len(strName)):
		file.write( struct.pack('B', strName[i]) )

#保存帧
def WriteFrame(binFile, keys):
	#保存帧数量
	binFile.write( struct.pack('<I', len(keys)) )
	print('len(keys) = ', len(keys))
	#保存帧编号
	for co in keys:
		binFile.write( struct.pack('<i', int(co[0])) )
	#保存帧关键帧值
	for co in keys:
		binFile.write( struct.pack('f', co[1]) )
	#保存帧
	def WriteFrame_Rotation(binFile, keys):
		#保存帧数量
		binFile.write( struct.pack('<I', len(keys)) )
		print('len(keys) = ', len(keys))
		#保存帧编号
		for co in keys:
			binFile.write( struct.pack('<i', int(co[0])) )
		#保存帧关键帧值
		for co in keys:
			print('co[1] = ', co[1])
			print('degrees co[1] = ', math.degrees(co[1]))
			binFile.write( struct.pack('f', math.degrees(co[1])) )

#--------------------------------------------保存动作关键帧---------------------------------------------
def f_get关键点(曲线):
	关键点 = []
	for framePoint in 曲线.keyframe_points:
		关键点.append(framePoint.handle_left)
		关键点.append(framePoint.co)
		关键点.append(framePoint.handle_right)
	return 关键点
def f_写出关键点(关键点容器, binFile):
	#关键点数量
	binFile.write( struct.pack('<I', len(关键点容器)) )	
	for Keys in 关键点容器:
		#控制柄
		for 控制点 in Keys:
			for 关键点 in 控制点:
				binFile.write( struct.pack('f', 关键点.x) )
				binFile.write( struct.pack('f', 关键点.y) )

def f_写出动作关键帧(binFile):
	binFile.write( struct.pack('<I', len(E_关键帧)) )
	
	for action in bpy.data.actions:
		SaveObjName(binFile, action.name)

		locationKeysX = []
		locationKeysY = []
		locationKeysZ = []
		rotationKeysX = []
		rotationKeysY = []
		rotationKeysZ = []
		scaleKeysX = []
		scaleKeysY = []
		scaleKeysZ = []
		#遍历曲线
		for 曲线 in action.fcurves:
			if 曲线.data_path == 'location' :
				if 曲线.array_index == 0 :
					locationKeysX.append(f_get关键点(曲线))
				elif 曲线.array_index == 1 :
					locationKeysY.append(f_get关键点(曲线))
				elif 曲线.array_index == 2 :
					locationKeysZ.append(f_get关键点(曲线))
			
			elif 曲线.data_path == 'reoation' :
				if 曲线.array_index == 0 :
					rotationKeysX.append(f_get关键点(曲线))
				elif 曲线.array_index == 1 :
					rotationKeysY.append(f_get关键点(曲线))
				elif 曲线.array_index == 2 :
					rotationKeysZ.append(f_get关键点(曲线))
			
			elif 曲线.data_path == 'scale' :
				if 曲线.array_index == 0 :
					scaleKeysX.append(f_get关键点(曲线))
				elif 曲线.array_index == 1 :
					scaleKeysY.append(f_get关键点(曲线))
				elif 曲线.array_index == 2 :
					scaleKeysZ.append(f_get关键点(曲线))

		#保存轴ID
		binFile.write( struct.pack('<I', len(E_关键帧_location)) )
		f_写出关键点(locationKeysX, binFile)
		f_写出关键点(locationKeysY, binFile)
		f_写出关键点(locationKeysZ, binFile)
		binFile.write( struct.pack('<I', len(E_关键帧_roation)) )
		f_写出关键点(rotationKeysX, binFile)
		f_写出关键点(rotationKeysY, binFile)
		f_写出关键点(rotationKeysZ, binFile)
		binFile.write( struct.pack('<I', len(E_关键帧_scale)) )
		f_写出关键点(scaleKeysX, binFile)
		f_写出关键点(scaleKeysY, binFile)
		f_写出关键点(scaleKeysZ, binFile)




#保存植被数据
def f_写出植被数据(binFile, obj):
	
	pass



#保存流体对象
def WriteFluidObj(binFile):
	#保存为流体域
	binFile.write( struct.pack('I', OT_FLUID) )


def f_保存导航(binFile, me):
	#保存对象类型
	binFile.write( struct.pack('<I', E_导航) )
	#顶点数量
	binFile.write( struct.pack('<I', len(me.vertices)) )
	for vert in me.vertices:
		for v in vert.co:
			binFile.write( struct.pack('<f', v) )
	binFile.write( struct.pack('<I', len(me.edges)) )
	for edge in me.edges:
		for e in edge.vertices:
			binFile.write( struct.pack('<I', e) )
			

	print("save")


def Engne_ExportPolaygons(context, select, path):
	scene = context.scene
	objs = []
	if select:
		objs = context.selected_objects
	else:
		for m in bpy.data.objects:
			objs.append(m)

	binFile = open(path, 'wb')
	#保存版本
	binFile.write( struct.pack('I', 1) )

	#--------------------------全局关键帧保存--------------------------
	f_写出动作关键帧(binFile)

	#迭代所有选择对象
	for obj in objs:
		#保存对象名称
		SaveObjName(binFile, obj.name)

		if obj.type == 'MESH' or obj.type == 'CURVE':
			
			#me = obj.data
			me = obj.to_mesh(scene, True, calc_tessface=False, settings='RENDER' if EXPORT_APPLY_MODIFIERS_RENDER else 'PREVIEW')
			bm = bmesh.new()
			bm.from_mesh(me)
			
			bmesh.ops.triangulate(bm, faces=bm.faces)
			bmesh.ops.rotate(bm, verts=bm.verts[:], cent=(1.0, 0.0, 0.0), matrix=mathutils.Matrix.Rotation(math.radians(-90.0), 3, 'X'))
			bmesh.ops.scale(bm, vec=mathutils.Vector((1.0, 1.0, 1.0)), space=mathutils.Matrix.Scale(1, 4, (1.0, 1.0, 1.0)), verts=bm.verts[:])
			#bmesh.ops.recalc_face_normals(bm, faces=bm.faces[:])

			bm.to_mesh(me)
			bm.free()



			#查找修改器 保存其他类型
			if len(obj.game.sensors) > 0 :
				for t in obj.game.sensors:
					if t.name == "导航":
						f_保存导航(binFile, me)
						break
			
			elif obj.modifiers.find('Fluidsim') >= 0:
				WriteFluidObj(binFile)
			else:
				
				#bmesh.ops.reverse_uvs(bm, faces=bm.faces[:]);
				#bmesh.ops.rotate_uvs(bm, faces=bm.faces[:], use_ccw=False);
				print('save model')
				#数据组 ---------------------------------------- 网格数据拷贝到缓存里 -------------------------------------------
				UVCoord = []
				Normal = []
				Vertex = []
				VIndex = []
				VWeight = []
				#FaIndex
				#记录顶点和法线 分配uv空间
				for vert in me.vertices:
					for v in vert.co:
						Vertex.append(v)
					for n in vert.normal:
						Normal.append(n)
					UVCoord.append(0.0)
					UVCoord.append(0.0)

					#权重数据
					'''groups = me.vertices[vert.index].groups
					if len(groups) > 0 :
						weightGroup = []
						for g in groups:
							#所在组的索引 当前顶点权重值
							groupID_weight = [g.group, g.weight]
							weightGroup.append(groupID_weight)
							
						VWeight.append(weightGroup)
					else:
						VWeight.append([])'''
					
				UVlayerID = 0
				for face in me.polygons:
					for ri in range(0, 3):
						i = face.vertices[ri]
						VIndex.append(struct.pack('<I', i))

						if len(me.uv_layers):
							ti = face.loop_indices[ri]
							uv = me.uv_layers[0].data[ti].uv
							UVCoord[i*2]	= uv[0]
							UVCoord[i*2+1]	= uv[1]
				
				
				
				#保存对象类型
				binFile.write( struct.pack('<I', 1) )
				
				'''----------------------------------------  网格写出  -------------------------------------------'''
				#保存定点数量
				binFile.write( struct.pack('<I', len(Vertex)) )
				
				#保存定点
				i = 0
				for vert in Vertex:
					s = struct.pack('<f', vert)
					binFile.write( s )
				#print("顶点数量", len(Vertex), i)
				#保存法线数量
				binFile.write( struct.pack('<I', len(Normal)) )
				#print("Normal", len(Normal))
				#保存法线
				for normal in Normal:
					binFile.write( struct.pack('<f', normal) )
					
				#保存纹理坐标数量
				binFile.write( struct.pack('<I', len(UVCoord)) )
				#print("UVCoord", len(UVCoord))
				#保存纹理坐标
				for uv in UVCoord:
					binFile.write( struct.pack('<f', uv) )
					
				#保存索引数量
				binFile.write( struct.pack('<I', len(VIndex)) )
				#print("VIndex", len(VIndex))
				#保存索引
				for index in VIndex:
					binFile.write( index )
				
				
				#保存顶点权重组数量
				'''binFile.write( struct.pack('B', len(obj.vertex_groups)) )
				binFile.write( struct.pack('I', len(VWeight)) )
				print("权重数量", len(VWeight))
				#保存顶点权重 --顶点索引--顶点权重--
				for indexAndWeight in VWeight :
					if len(indexAndWeight) > 0 :
						#写出权重组数量
						binFile.write(struct.pack('B', len(indexAndWeight)))
						for weightGroup in indexAndWeight :
							binFile.write( struct.pack('I', weightGroup[0]) )
							binFile.write( struct.pack('f', weightGroup[1]) )
					else:
						binFile.write( struct.pack('B', 0) )'''

				
				
				

		if obj.type == 'LAMP':
			binFile.write( struct.pack('<I', 2) )
			
			#保存灯光类型
			if obj.data.type == 'POINT':
				binFile.write( struct.pack('<I', 1) )
			elif obj.data.type == 'SUN':
				binFile.write( struct.pack('<I', 2) )
			elif obj.data.type == 'SPOT':
				binFile.write( struct.pack('<I', 3) )
			else:
				binFile.write( struct.pack('<I', 2) )
			
			#保存灯光亮度
			binFile.write( struct.pack('<f', obj.data.energy) )
			

		if obj.type == 'CAMERA':
			binFile.write( struct.pack('<I', 3) )
			#保存摄像机视野角度 弧度值
			binFile.write( struct.pack('<f', obj.data.angle) )


		#是否有动画

		#保存帧动画
		if obj.animation_data != None:
			#写入有动画数据
			binFile.write( struct.pack('<I', 111) )
			
			locationX = []
			locationY = []
			locationZ = []
			rotationX = []
			rotationY = []
			rotationZ = []
			scaleX = []
			scaleY = []
			scaleZ = []
			
			for fcurve in obj.animation_data.action.fcurves:
				if fcurve.data_path == 'location':
					if fcurve.array_index == 0 :
						#保存动画X轴移动动画
						for framePoint in fcurve.keyframe_points:
							locationX.append(framePoint.co)
							
					if fcurve.array_index == 1 :
						#保存动画Y轴移动动画
						for framePoint in fcurve.keyframe_points:
							locationY.append(framePoint.co)
							
					if fcurve.array_index == 2 :
						#保存动画Z轴移动动画
						for framePoint in fcurve.keyframe_points:
							locationZ.append(framePoint.co)
							
				elif fcurve.data_path == 'rotation_euler':
					if fcurve.array_index == 0 :
						#保存动画X轴旋转动画
						for framePoint in fcurve.keyframe_points:
							rotationX.append(framePoint.co)
					if fcurve.array_index == 1 :
						#保存动画Y轴旋转动画
						for framePoint in fcurve.keyframe_points:
							rotationY.append(framePoint.co)
					if fcurve.array_index == 2 :
						#保存动画Z轴旋转动画
						for framePoint in fcurve.keyframe_points:
							rotationZ.append(framePoint.co)
							
						
				elif fcurve.data_path == 'scale':
					if fcurve.array_index == 0 :
						#保存动画X轴缩放动画
						for framePoint in fcurve.keyframe_points:
							scaleX.append(framePoint.co)
					if fcurve.array_index == 1 :
						#保存动画Y轴缩放动画
						for framePoint in fcurve.keyframe_points:
							scaleY.append(framePoint.co)
					if fcurve.array_index == 2 :
						#保存动画Z轴缩放动画
						for framePoint in fcurve.keyframe_points:
							scaleZ.append(framePoint.co)
					
				#obj.animation_data.action.groups['Location'].channels[0].keyframe_points[0].co[1]	
			#保存动画X轴移动动画帧数量
			print(obj.name)
			WriteFrame(binFile, locationX)
			#保存动画Z轴移动动画帧数量
			WriteFrame(binFile, locationZ)
			#保存动画Y轴移动动画帧数量
			WriteFrame(binFile, locationY)
			
			
			print(rotationX)
			#保存动画X轴旋转动画帧数量
			WriteFrame_Rotation(binFile, rotationX)
			#保存动画Z轴旋转动画帧数量
			WriteFrame_Rotation(binFile, rotationZ)
			#保存动画Y轴旋转动画帧数量
			WriteFrame_Rotation(binFile, rotationY)
			
			
			print(scaleX)
			#保存动画X轴缩放动画帧数量
			WriteFrame(binFile, scaleX)
			#保存动画Z轴缩放动画帧数量
			WriteFrame(binFile, scaleZ)
			#保存动画Y轴缩放动画帧数量
			WriteFrame(binFile, scaleY)
			
			
		else:
			binFile.write( struct.pack('I', 0) )
			print('note')

		#写入无动画数据
		#保存对象型位置
		binFile.write( struct.pack('<f', obj.location[0]) )
		binFile.write( struct.pack('<f', obj.location[2]) )
		binFile.write( struct.pack('<f', obj.location[1]) )
		#保存对象旋转角度
		binFile.write( struct.pack('<f', math.degrees(obj.rotation_euler[0])) )
		binFile.write( struct.pack('<f', math.degrees(obj.rotation_euler[2])) )
		binFile.write( struct.pack('<f', math.degrees(obj.rotation_euler[1])) )
		#保存对象缩放比例
		binFile.write( struct.pack('<f', obj.scale[0]) )
		binFile.write( struct.pack('<f', obj.scale[2]) )
		binFile.write( struct.pack('<f', obj.scale[1]) )



	binFile.write( struct.pack('<I', 0xffffffff) )

	binFile.close()


def Engne_ExportPolaygons_1(context, select, path):
	objs = []
	if select:
		objs = context.selected_objects
	else:
		for m in bpy.data.objects:
			objs.append(m)

	binFile = open(path, 'wb')
	#保存版本
	binFile.write( struct.pack('I', 1) )


	#迭代所有选择对象
	for obj in objs:
		#保存对象名称
		SaveObjName(binFile, obj.name)

	if obj.type == 'MESH' or obj.type == 'CURVE':
		mesh = obj.data
		if not mesh.tessfaces and mesh.polygons:
			mesh.calc_tessface()
		has_uv = bool(mesh.tessface_uv_textures)
		has_vcol = bool(mesh.tessface_vertex_colors)
		
		if has_uv :
			active_uv_layer = mesh.tessface_uv_textures.active
		if has_vcol :
			active_col_layer = mesh.tessface_vertex_colors.active
			
		mesh_verts = mesh.vertices
		ply_verts = []
		vdict = [{} for i in range(len(mesh_verts))]
		ply_faces = [[] for f in range(len(mesh.tessfaces))]
		
		
		for i, f in enumerate(mesh.tessfaces):
			print(i, f)

	binFile.write( struct.pack('I', 0xffffffff) )
	binFile.close()



class Engine_ExportMM(bpy.types.Operator, ExportHelper):
	bl_idname = "export_scene.ms"
	bl_label = 'Export MS'
	bl_options = {'PRESET'}

	#filename_ext = StringProperty(subtype='FILE_PATH')
	filename_ext = '.ms'
	filepath = StringProperty(subtype='FILE_PATH')

	SelectOnly = BoolProperty(name="导出选定对象", description="导出选定对象", default=True)


	def execute(self, context):
		#self.filename_ext = "mbt.mm"
		#from.import export_obj
		#selectOnly = self.SelectOnly[1]['default']
		Engne_ExportPolaygons(context, self.SelectOnly, self.filepath)
		#Engine_SaveModel(context, self.SelectOnly, self.filepath)
		return {'FINISHED'}
		#return export_obj.save(self, context, **keywords)


def menu_func_export(self, context):
	self.layout.operator(Engine_ExportMM.bl_idname, text="场景文件 (.ms)")


def register():
	bpy.utils.register_module(__name__)
	bpy.types.INFO_MT_file_export.append(menu_func_export)

def unregister():
	bpy.utils.unregister_module(__name__)
	bpy.types.INFO_MT_file_export.remove(menu_func_export)


if __name__ == "__main__":
	register()


